#ifndef __GlListener_h__
#define __GlListener_h__

#include <vector>
#include "GlId.h"
#include "GlMain.h"

namespace GraphicLibrary
{
	template<typename ListenerType>
		class Distributor;

	///
	/// This is the base class of Listener. Never inherit from this class. Inherit from Listener.
	class GlExport _Listener
		: public Id
	{
		public:
			///
			/// Distributor class type to connect.
			typedef Distributor<_Listener>	MyDistributor;
			/// Do not call this manually.
			/// This function is called from the Distributor when the listener is connected to it.
			/// @param distributor The Distributor it is connected to.
			virtual void connectedTo(const MyDistributor *distributor);
			/// Do not call this manually.
			/// This function is called from the Distributor when the listener is disconnected from it.
			/// @param distributor The Distributor it is disconnected from.
			virtual void disconnectedFrom(const MyDistributor *distributor);
			///
			/// This function should disconnect from the connected Distributor(s).
			virtual ~_Listener();

		protected:
			/// This function is called after the listener is fully connected to the distributor.
			/// Override this to respond to this message.
			/// @param distributor The Distributor we are connected to.
			virtual void afterConnected(const MyDistributor *distributor);
			/// This function is called after the listener is fully connected to the distributor.
			/// Override this to respond to this message.
			/// @param distributor The Distributor we are disconnected from.
			virtual void afterDisconnected(const MyDistributor *distributor);
	};

	/// This class is intended to be a base class for listeners.
	/// @param ListenerType This is the type the listener is receiving information about.
	template<typename ListenerType>
		class Listener
			: public _Listener
		{
			public:
				///
				/// Initially it is not connected to any Distributor.
				inline Listener();
				/// Do not call this manually.
				/// This function is called from the Distributor when the listener is connected to it.
				/// @param distributor The Distributor it is connected to.
				virtual void connectedTo(const MyDistributor *distributor);
				/// Do not call this manually.
				/// This function is called from the Distributor when the listener is disconnected from it.
				/// @param distributor The Distributor it is disconnected from.
				virtual void disconnectedFrom(const MyDistributor *distributor);
				///
				/// @return Returns if we are connected to any Distributor or not.
				inline bool isConnected() const;
				///
				/// @return Returns the Distributor it is connected to.
				inline const MyDistributor* getDistributor() const;
				///
				/// Disconnect connected Distributor if there is one.
				virtual ~Listener();
			private:
				const MyDistributor*	mDistributor;	///< The Distributor it is connected to.

				///
				/// Disconnects itself from it's Distributor
				void disconnect();
		};

	///
	/// This type of Listener can connect to multiple Distributor.
	template<typename ListenerType>
		class MultiListener
			: public _Listener
		{
			public:
				inline MultiListener();
				/// Do not call this manually.
				/// This function is called from the Distributor when the listener is connected to it.
				/// @param distributor The Distributor it is connected to.
				virtual void connectedTo(const MyDistributor *distributor);
				/// Do not call this manually.
				/// This function is called from the Distributor when the listener is disconnected from it.
				/// @param distributor The Distributor it is disconnected from.
				virtual void disconnectedFrom(const MyDistributor *distributor);
				/// @param distributor to check.
				/// @return Returns true if it is connected to the given Distributor.
				inline bool isConnectedTo(const MyDistributor *distributor) const;
				///
				/// Disconnect all connected Distributor.
				virtual ~MultiListener();
			private:
				///
				/// MyDistributor pointer storage type
				typedef std::vector< const MyDistributor* >	MyDistributorArray;
				///
				/// Class to compare MyDistributors pointers by id
				class Less
				{
					public:
						inline bool operator () (const MyDistributor *left, const MyDistributor *right) const;
				};

				///
				/// Stores pointer to the connected Distributor objects
				MyDistributorArray*	mDistributors;	//>
		};
}

#include "GlListener.inl"

#endif // __GlListener_h__
